#include <CType.h>

extern int8_t BS_OEMName;
extern int16_t BS_BytesPerSec;
extern int8_t BS_SecPerCls;
extern int16_t BS_ReserveSec;
extern int8_t BS_FATCnt;
extern int16_t BS_RootDir;
extern int16_t BS_SecCnt16;
extern int8_t BS_MediaType;
extern int16_t BS_FATSize16;
extern int16_t BS_SecPerTrack;
extern int16_t BS_HeadCnt;
extern int32_t BS_HiddenSec;
extern int32_t BS_SecCnt32;
extern int8_t BS_DrvNum;
extern int8_t BS_Reserve1;
extern int8_t BS_BootFlag;
extern int8_t BS_VolumeID;
extern int8_t BS_FSType;
extern int8_t BS_VolumeLabel;

#define BS_RootDir                  0xE0
#define BS_SectorSize               512
#define BS_RootDirSecCnt            14
#define BS_FatSecSize               9
#define BS_RootFatSecOffset         19
#define BS_SecInTrack               0x24
#define BS_SecInTrackInHd           0x12
#define BS_FileClsOffset            26
#define BS_StartIP                  0x7C00

#if 0
#define BS_ITOA_DATA_OFFSET         0x400
#endif
#define BS_SWAP_DATA_OFFSET         0x0400
#define BS_FAT_DATA_OFFSET          0x1000
#define BS_LOADER_CS_OFFSET         0x1000
#define BS_LOADER_IP_OFFSET         0x0000

#define BS_FILENAME_LEN             11
#define BS_LOADERFILENAME           "LDR     BIN"

#if 0
int8_t * itoa(int16_t v);

void display(int8_t *s, int16_t len);
#endif

void loadFile(int16_t clsNum);

int16_t filenameCheck(int8_t * src, int8_t * dst);

uint16_t loadSec(int16_t addr, int16_t offset);

main()
{
    int16_t i, j;
    int16_t r, p;

    p = BS_StartIP + BS_FAT_DATA_OFFSET;

    for (i = 1;i <= BS_FatSecSize; i++, p += BS_SectorSize)
        {
        loadSec(p, i);
        }

    r = BS_RootFatSecOffset;

    for (j = 0; j < BS_RootDirSecCnt; j++, r++)
        {
        p = BS_StartIP + BS_SWAP_DATA_OFFSET;
        loadSec(p, r);

        for (i = 0; i < 16; i++, p += 32)
            {
            if (filenameCheck(BS_LOADERFILENAME, p) == 0)
                {
                loadFile(*(int16_t *)(p + BS_FileClsOffset));
                asm mov ax, BS_LOADER_CS_OFFSET;
                asm push ax;
                asm mov ax, BS_LOADER_IP_OFFSET;
                asm push ax;
                asm retf;
                }
            }
        }
LblLoop:
    asm jmp LblLoop;
}

void loadFile(int16_t clsNum)
{
    int16_t t, s;
    int16_t sec;
    uint16_t addr = BS_LOADER_IP_OFFSET;
    uint16_t es_r = BS_LOADER_CS_OFFSET;

    asm mov es, es_r;

    while(clsNum != 0xfff)
        {
        sec = clsNum - 2 + BS_RootDirSecCnt + BS_RootFatSecOffset;
        loadSec(addr, sec);

        addr += BS_SectorSize;

        if (addr == 0)
            {
            es_r += 0x1000;
            asm mov es, es_r;
            }

        t = (clsNum >> 1) * 3;

        s = BS_StartIP + BS_FAT_DATA_OFFSET + t;

        if (clsNum & 1)
            {
            clsNum = ((*(uint8_t *)(s + 1)) >> 4)
                        | ((*(uint8_t *)(s + 2)) << 4);
            }
        else
            {
            clsNum = (*(int16_t *)(s)) & 0xFFF;
            }
        }

    return;
}

uint16_t loadSec(int16_t addr, int16_t offset)
{
    uint8_t sec, hd, trk;

    trk = offset / BS_SecInTrack;
    sec = offset % BS_SecInTrack;
    hd = sec / BS_SecInTrackInHd;
    sec = (sec % BS_SecInTrackInHd) + 1;

    asm mov ax, 0x0201;
    asm mov bx, addr;
    asm mov cl, sec;
    asm mov ch, trk;
    asm mov dh, hd;
    asm mov dl, 0;
    asm int 0x13;
    asm cmp ah, 0;
    asm jnz ldsFail;
    return 0;
ldsFail:
    return -1;
}

int16_t filenameCheck(int8_t * src, int8_t * dst)
{
    int16_t i;

    for (i = 0; i < BS_FILENAME_LEN; i++)
        {
        if (*src++ != *dst++)
            return -1;
        }

    return 0;
}

#if 0
int8_t * itoa(int16_t v)
{
    int8_t * buf;
    int16_t f = 0;
    int16_t i = 0;

    buf = (int8_t *)BS_StartIP + BS_ITOA_DATA_OFFSET + 10;

    if (v < 0)
        f = 1, v = -v;

    while(v > 0)
        {
        buf[i--] = v % 10 + '0';
        v = v / 10;
        }

    if (f == 1)
        buf[i--] = '-';

    return &buf[i+1];
}

void display(int8_t *s, int16_t len)
{
    int8_t c, *p = NULL;
    if (len != 0) p = s + len;
    while (((c = s[0]) != '\0') && p != s)
    {
        asm mov al, c;
        asm mov ah, 0xE;
        asm mov bl, 0x7;
        asm int 0x10;
        s++;
    }
}
#endif

